core: Make commit always operate on directory contents, not file list
authorColin Walters <walters@verbum.org>
Sun, 27 Nov 2011 23:03:05 +0000 (18:03 -0500)
committerColin Walters <walters@verbum.org>
Mon, 28 Nov 2011 17:57:25 +0000 (12:57 -0500)
This simplifies things significantly, at some cost in flexibility.
We'll later add the ability to e.g. filter out files by regular
expression.

src/libostree/ostree-repo.c
src/libostree/ostree-repo.h
src/ostree/ot-builtin-commit.c
tests/t0000-basic.sh
tests/t0004-compose.sh

index 545591dd9dae11cadcaec29ac8d5d49b016d6e07..337b61c1a8e768a153e799793efc83571932cff7 100644 (file)
@@ -698,7 +698,7 @@ ostree_repo_load_variant_checked (OstreeRepo  *self,
 
 static gboolean
 import_directory_meta (OstreeRepo  *self,
-                       const char *path,
+                       GFile       *f,
                        GVariant  **out_variant,
                        GChecksum **out_checksum,
                        GError    **error)
@@ -706,11 +706,8 @@ import_directory_meta (OstreeRepo  *self,
   gboolean ret = FALSE;
   GChecksum *ret_checksum = NULL;
   GVariant *dirmeta = NULL;
-  GFile *f = NULL;
   GFileInfo *f_info = NULL;
 
-  f = ot_gfile_new_for_path (path);
-
   f_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO,
                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                               NULL, error);
@@ -725,12 +722,17 @@ import_directory_meta (OstreeRepo  *self,
     goto out;
 
   ret = TRUE;
-  *out_variant = dirmeta;
-  dirmeta = NULL;
-  *out_checksum = ret_checksum;
-  ret_checksum = NULL;
+  if (out_variant)
+    {
+      *out_variant = dirmeta;
+      dirmeta = NULL;
+    }
+  if (out_checksum)
+    {
+      *out_checksum = ret_checksum;
+      ret_checksum = NULL;
+    }
  out:
-  g_clear_object (&f);
   g_clear_object (&f_info);
   if (ret_checksum)
     g_checksum_free (ret_checksum);
@@ -951,85 +953,194 @@ ostree_repo_store_packfile (OstreeRepo       *self,
   return ret;
 }
 
-typedef struct _ParsedTreeData ParsedTreeData;
-typedef struct _ParsedDirectoryData ParsedDirectoryData;
+static GVariant *
+create_empty_gvariant_dict (void)
+{
+  GVariantBuilder builder;
+  g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sv}"));
+  return g_variant_builder_end (&builder);
+}
 
-static void parsed_tree_data_free (ParsedTreeData *pdata);
+gboolean      
+ostree_repo_write_ref (OstreeRepo  *self,
+                       const char  *remote,
+                       const char  *name,
+                       const char  *rev,
+                       GError     **error)
+{
+  gboolean ret = FALSE;
+  OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  GFile *dir = NULL;
 
-struct _ParsedDirectoryData {
-  ParsedTreeData *tree_data;
-  char *metadata_sha256;
-  GVariant *meta_data;
-};
+  if (remote == NULL)
+    dir = g_object_ref (priv->local_heads_dir);
+  else
+    {
+      dir = g_file_get_child (priv->remote_heads_dir, remote);
 
-static void
-parsed_directory_data_free (ParsedDirectoryData *pdata)
-{
-  if (pdata == NULL)
-    return;
-  parsed_tree_data_free (pdata->tree_data);
-  g_free (pdata->metadata_sha256);
-  ot_clear_gvariant (&pdata->meta_data);
-  g_free (pdata);
-}
+      if (!ot_gfile_ensure_directory (dir, FALSE, error))
+        goto out;
+    }
 
-struct _ParsedTreeData {
-  GHashTable *files;  /* char* filename -> char* checksum */
-  GHashTable *directories;  /* char* dirname -> ParsedDirectoryData* */
-};
+  if (!write_checksum_file (dir, name, rev, error))
+    goto out;
 
-static ParsedTreeData *
-parsed_tree_data_new (void)
-{
-  ParsedTreeData *ret = g_new0 (ParsedTreeData, 1);
-  ret->files = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                      (GDestroyNotify)g_free, 
-                                      (GDestroyNotify)g_free);
-  ret->directories = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                            (GDestroyNotify)g_free, 
-                                            (GDestroyNotify)parsed_directory_data_free);
+  ret = TRUE;
+ out:
+  g_clear_object (&dir);
   return ret;
 }
 
-static void
-parsed_tree_data_free (ParsedTreeData *pdata)
+static gboolean
+import_commit (OstreeRepo *self,
+               const char   *branch,
+               const char   *parent,
+               const char   *subject,
+               const char   *body,
+               GVariant     *metadata,
+               GChecksum    *root_contents_checksum,
+               GChecksum    *root_metadata_checksum,
+               GChecksum   **out_commit,
+               GError      **error)
 {
-  if (pdata == NULL)
-    return;
-  g_hash_table_destroy (pdata->files);
-  g_hash_table_destroy (pdata->directories);
-  g_free (pdata);
-}
+  gboolean ret = FALSE;
+  GChecksum *ret_commit = NULL;
+  GVariant *commit = NULL;
+  GDateTime *now = NULL;
 
-static GVariant *
-create_empty_gvariant_dict (void)
-{
-  GVariantBuilder builder;
-  g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sv}"));
-  return g_variant_builder_end (&builder);
+  g_assert (branch != NULL);
+  g_assert (subject != NULL);
+
+  now = g_date_time_new_now_utc ();
+  commit = g_variant_new ("(u@a{sv}ssstss)",
+                          GUINT32_TO_BE (OSTREE_COMMIT_VERSION),
+                          metadata ? metadata : create_empty_gvariant_dict (),
+                          parent ? parent : "",
+                          subject, body ? body : "",
+                          GUINT64_TO_BE (g_date_time_to_unix (now)),
+                          g_checksum_get_string (root_contents_checksum),
+                          g_checksum_get_string (root_metadata_checksum));
+  g_variant_ref_sink (commit);
+  if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
+                               commit, &ret_commit, error))
+    goto out;
+
+  if (!ostree_repo_write_ref (self, NULL, branch, g_checksum_get_string (ret_commit), error))
+    goto out;
+
+  ret = TRUE;
+  if (out_commit)
+    {
+      *out_commit = ret_commit;
+      ret_commit = NULL;
+    }
+ out:
+  if (ret_commit)
+    g_checksum_free (ret_commit);
+  ot_clear_gvariant (&commit);
+  if (now)
+    g_date_time_unref (now);
+  return ret;
 }
 
 static gboolean
-import_parsed_tree (OstreeRepo    *self,
-                    ParsedTreeData  *tree,
-                    GChecksum      **out_checksum,
-                    GError         **error)
+import_directory_recurse (OstreeRepo           *self,
+                          GFile                *base,
+                          GFile                *dir,
+                          GChecksum           **out_contents_checksum,
+                          GChecksum           **out_metadata_checksum,
+                          GCancellable         *cancellable,
+                          GError              **error)
 {
   gboolean ret = FALSE;
-  GVariant *serialized_tree = NULL;
+  GError *temp_error = NULL;
+  GChecksum *ret_metadata_checksum = NULL;
+  GChecksum *ret_contents_checksum = NULL;
+  GFileEnumerator *dir_enum = NULL;
+  GFileInfo *child_info = NULL;
+  GFile *child = NULL;
+  GHashTable *file_checksums = NULL;
+  GHashTable *dir_metadata_checksums = NULL;
+  GHashTable *dir_contents_checksums = NULL;
+  GChecksum *child_file_checksum = NULL;
+  gboolean did_exist;
   gboolean builders_initialized = FALSE;
   GVariantBuilder files_builder;
   GVariantBuilder dirs_builder;
   GHashTableIter hash_iter;
   GSList *sorted_filenames = NULL;
   GSList *iter;
+  GVariant *serialized_tree = NULL;
   gpointer key, value;
 
+  if (!import_directory_meta (self, dir, NULL, &ret_metadata_checksum, error))
+    goto out;
+
+  dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO, 
+                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                        cancellable, 
+                                        error);
+  if (!dir_enum)
+    goto out;
+  
+  file_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                          (GDestroyNotify)g_free, (GDestroyNotify)g_free);
+  dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                  (GDestroyNotify)g_free, (GDestroyNotify)g_free);
+  dir_contents_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                  (GDestroyNotify)g_free, (GDestroyNotify)g_free);
+
+  while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
+    {
+      const char *name = g_file_info_get_name (child_info);
+
+      g_clear_object (&child);
+      child = g_file_get_child (dir, name);
+
+      if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
+        {
+          GChecksum *child_dir_metadata_checksum;
+          GChecksum *child_dir_contents_checksum;
+
+          if (!import_directory_recurse (self, base, child, &child_dir_contents_checksum,
+                                         &child_dir_metadata_checksum, cancellable, error))
+            goto out;
+
+          g_hash_table_replace (dir_contents_checksums, g_strdup (name),
+                                g_strdup (g_checksum_get_string (child_dir_contents_checksum)));
+          g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
+                                g_strdup (g_checksum_get_string (child_dir_metadata_checksum)));
+          g_checksum_free (child_dir_contents_checksum);
+          g_checksum_free (child_dir_metadata_checksum);
+        }
+      else
+        {
+          if (child_file_checksum)
+            g_checksum_free (child_file_checksum);
+          if (!ostree_checksum_file (child, OSTREE_OBJECT_TYPE_FILE, &child_file_checksum, cancellable, error))
+            goto out;
+          
+          if (!ostree_repo_store_object_trusted (self, child, g_checksum_get_string (child_file_checksum),
+                                                 OSTREE_OBJECT_TYPE_FILE, FALSE, &did_exist, error))
+            goto out;
+
+          g_hash_table_replace (file_checksums, g_strdup (name),
+                                g_strdup (g_checksum_get_string (child_file_checksum)));
+        }
+
+      g_clear_object (&child_info);
+    }
+  if (temp_error != NULL)
+    {
+      g_propagate_error (error, temp_error);
+      goto out;
+    }
+
   g_variant_builder_init (&files_builder, G_VARIANT_TYPE ("a(ss)"));
   g_variant_builder_init (&dirs_builder, G_VARIANT_TYPE ("a(sss)"));
   builders_initialized = TRUE;
 
-  g_hash_table_iter_init (&hash_iter, tree->files);
+  g_hash_table_iter_init (&hash_iter, file_checksums);
   while (g_hash_table_iter_next (&hash_iter, &key, &value))
     {
       const char *name = key;
@@ -1043,14 +1154,14 @@ import_parsed_tree (OstreeRepo    *self,
       const char *name = iter->data;
       const char *value;
 
-      value = g_hash_table_lookup (tree->files, name);
+      value = g_hash_table_lookup (file_checksums, name);
       g_variant_builder_add (&files_builder, "(ss)", name, value);
     }
-
+  
   g_slist_free (sorted_filenames);
   sorted_filenames = NULL;
 
-  g_hash_table_iter_init (&hash_iter, tree->directories);
+  g_hash_table_iter_init (&hash_iter, dir_metadata_checksums);
   while (g_hash_table_iter_next (&hash_iter, &key, &value))
     {
       const char *name = key;
@@ -1062,17 +1173,11 @@ import_parsed_tree (OstreeRepo    *self,
   for (iter = sorted_filenames; iter; iter = iter->next)
     {
       const char *name = iter->data;
-      GChecksum *dir_checksum = NULL;
-      ParsedDirectoryData *dir;
-
-      dir = g_hash_table_lookup (tree->directories, name);
-
-      if (!import_parsed_tree (self, dir->tree_data, &dir_checksum, error))
-        goto out;
 
       g_variant_builder_add (&dirs_builder, "(sss)",
-                             name, g_checksum_get_string (dir_checksum), dir->metadata_sha256);
-      g_checksum_free (dir_checksum);
+                             name,
+                             g_hash_table_lookup (dir_contents_checksums, name),
+                             g_hash_table_lookup (dir_metadata_checksums, name));
     }
 
   g_slist_free (sorted_filenames);
@@ -1085,11 +1190,28 @@ import_parsed_tree (OstreeRepo    *self,
                                    g_variant_builder_end (&dirs_builder));
   builders_initialized = FALSE;
   g_variant_ref_sink (serialized_tree);
-  if (!import_gvariant_object (self, OSTREE_SERIALIZED_TREE_VARIANT, serialized_tree, out_checksum, error))
+
+  if (!import_gvariant_object (self, OSTREE_SERIALIZED_TREE_VARIANT, serialized_tree, &ret_contents_checksum, error))
     goto out;
-  
+
+  *out_metadata_checksum = ret_metadata_checksum;
+  ret_metadata_checksum = NULL;
+  *out_contents_checksum = ret_contents_checksum;
+  ret_contents_checksum = NULL;
   ret = TRUE;
  out:
+  g_clear_object (&dir_enum);
+  g_clear_object (&child);
+  g_clear_object (&child_info);
+  g_hash_table_destroy (file_checksums);
+  g_hash_table_destroy (dir_metadata_checksums);
+  g_hash_table_destroy (dir_contents_checksums);
+  if (ret_metadata_checksum)
+    g_checksum_free (ret_metadata_checksum);
+  if (ret_contents_checksum)
+    g_checksum_free (ret_contents_checksum);
+  if (child_file_checksum)
+    g_checksum_free (child_file_checksum);
   g_slist_free (sorted_filenames);
   if (builders_initialized)
     {
@@ -1100,360 +1222,23 @@ import_parsed_tree (OstreeRepo    *self,
   return ret;
 }
 
-static gboolean
-check_path (const char *filename,
-            GError    **error)
-{
-  gboolean ret = FALSE;
-
-  if (!*filename)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Invalid empty filename");
-      goto out;
-    }
-
-  if (strcmp (filename, ".") == 0)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Self-reference '.' in filename '%s' not allowed (yet)", filename);
-      goto out;
-    }
-  
-  if (ot_util_filename_has_dotdot (filename))
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Path uplink '..' in filename '%s' not allowed (yet)", filename);
-      goto out;
-    }
-  
-  if (g_path_is_absolute (filename))
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Absolute filename '%s' not allowed (yet)", filename);
-      goto out;
-    }
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-static gboolean
-add_one_directory_to_tree_and_import (OstreeRepo   *self,
-                                      const char     *basename,
-                                      const char     *abspath,
-                                      ParsedTreeData *tree,
-                                      ParsedDirectoryData **dir, /*inout*/
-                                      GError        **error)
-{
-  gboolean ret = FALSE;
-  GVariant *dirmeta = NULL;
-  GChecksum *dir_meta_checksum = NULL;
-  ParsedDirectoryData *dir_value = *dir;
-  
-  g_assert (tree != NULL);
-
-  if (!import_directory_meta (self, abspath, &dirmeta, &dir_meta_checksum, error))
-    goto out;
-
-  if (dir_value)
-    {
-      ot_clear_gvariant (&dir_value->meta_data);
-      dir_value->meta_data = dirmeta;
-    }
-  else
-    {
-      dir_value = g_new0 (ParsedDirectoryData, 1);
-      dir_value->tree_data = parsed_tree_data_new ();
-      dir_value->metadata_sha256 = g_strdup (g_checksum_get_string (dir_meta_checksum));
-      dir_value->meta_data = dirmeta;
-      g_hash_table_insert (tree->directories, g_strdup (basename), dir_value);
-    }
-
-  ret = TRUE;
-  *dir = dir_value;
- out:
-  if (dir_meta_checksum)
-    g_checksum_free (dir_meta_checksum);
-  return ret;
-}
-
-static gboolean
-add_one_file_to_tree_and_import (OstreeRepo   *self,
-                                 const char     *basename,
-                                 const char     *abspath,
-                                 ParsedTreeData *tree,
-                                 GError        **error)
-{
-  gboolean ret = FALSE;
-  GChecksum *checksum = NULL;
-  gboolean did_exist;
-  GFile *f = NULL;
-  
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-  g_assert (tree != NULL);
-
-  f = ot_gfile_new_for_path (abspath);
-
-  if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE, &checksum, NULL, error))
-    goto out;
-
-  if (!ostree_repo_store_object_trusted (self, f, g_checksum_get_string (checksum),
-                                         OSTREE_OBJECT_TYPE_FILE, FALSE, &did_exist, error))
-    goto out;
-
-  g_hash_table_replace (tree->files, g_strdup (basename),
-                        g_strdup (g_checksum_get_string (checksum)));
-
-  ret = TRUE;
- out:
-  g_clear_object (&f);
-  if (checksum)
-    g_checksum_free (checksum);
-  return ret;
-}
-
-static gboolean
-add_one_path_to_tree_and_import (OstreeRepo     *self,
-                                 const char     *base,
-                                 const char     *filename,
-                                 ParsedTreeData *tree,
-                                 GError        **error)
-{
-  gboolean ret = FALSE;
-  GPtrArray *components = NULL;
-  struct stat stbuf;
-  char *component_abspath = NULL;
-  ParsedTreeData *current_tree = tree;
-  const char *component = NULL;
-  const char *file_sha1;
-  char *abspath = NULL;
-  ParsedDirectoryData *dir;
-  int i;
-  gboolean is_directory;
-
-  if (!check_path (filename, error))
-    goto out;
-
-  abspath = g_build_filename (base, filename, NULL);
-
-  if (lstat (abspath, &stbuf) < 0)
-    {
-      ot_util_set_error_from_errno (error, errno);
-      goto out;
-    }
-  is_directory = S_ISDIR(stbuf.st_mode);
-       
-  if (components)
-    g_ptr_array_free (components, TRUE);
-  components = ot_util_path_split (filename);
-  g_assert (components->len > 0);
-
-  current_tree = tree;
-  for (i = 0; i < components->len; i++)
-    {
-      component = components->pdata[i];
-      g_free (component_abspath);
-      component_abspath = ot_util_path_join_n (base, components, i);
-      file_sha1 = g_hash_table_lookup (current_tree->files, component);
-      dir = g_hash_table_lookup (current_tree->directories, component);
-
-      g_assert_cmpstr (component, !=, ".");
-
-      if (i < components->len - 1)
-        {
-          if (file_sha1 != NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Encountered non-directory '%s' in '%s'",
-                           component,
-                           filename);
-              goto out;
-            }
-          /* Implicitly add intermediate directories */
-          if (!add_one_directory_to_tree_and_import (self, component,
-                                                     component_abspath, current_tree, &dir,
-                                                     error))
-            goto out;
-          g_assert (dir != NULL);
-          current_tree = dir->tree_data;
-        }
-      else if (is_directory)
-        {
-          if (file_sha1 != NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "File '%s' can't be overwritten by directory",
-                           filename);
-              goto out;
-            }
-          if (!add_one_directory_to_tree_and_import (self, component,
-                                                     abspath, current_tree, &dir,
-                                                     error))
-            goto out;
-        }
-      else 
-        {
-          g_assert (!is_directory);
-          if (dir != NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "File '%s' can't be overwritten by directory",
-                           filename);
-              goto out;
-            }
-          if (!add_one_file_to_tree_and_import (self, component, abspath,
-                                                current_tree, error))
-            goto out;
-        }
-    }
-
-  ret = TRUE;
- out:
-  if (components)
-    g_ptr_array_unref (components);
-  g_free (component_abspath);
-  g_free (abspath);
-  return ret;
-}
-
 gboolean      
-ostree_repo_write_ref (OstreeRepo  *self,
-                       const char  *remote,
-                       const char  *name,
-                       const char  *rev,
-                       GError     **error)
-{
-  gboolean ret = FALSE;
-  OstreeRepoPrivate *priv = GET_PRIVATE (self);
-  GFile *dir = NULL;
-
-  if (remote == NULL)
-    dir = g_object_ref (priv->local_heads_dir);
-  else
-    {
-      dir = g_file_get_child (priv->remote_heads_dir, remote);
-
-      if (!ot_gfile_ensure_directory (dir, FALSE, error))
-        goto out;
-    }
-
-  if (!write_checksum_file (dir, name, rev, error))
-    goto out;
-
-  ret = TRUE;
- out:
-  g_clear_object (&dir);
-  return ret;
-}
-
-static gboolean
-commit_parsed_tree (OstreeRepo *self,
+ostree_repo_commit (OstreeRepo *self,
                     const char   *branch,
                     const char   *parent,
                     const char   *subject,
                     const char   *body,
                     GVariant     *metadata,
-                    ParsedDirectoryData *root,
+                    GFile        *dir,
                     GChecksum   **out_commit,
+                    GCancellable *cancellable,
                     GError      **error)
-{
-  gboolean ret = FALSE;
-  GChecksum *root_checksum = NULL;
-  GChecksum *ret_commit = NULL;
-  GVariant *commit = NULL;
-  GDateTime *now = NULL;
-
-  g_assert (branch != NULL);
-  g_assert (subject != NULL);
-
-  if (!import_parsed_tree (self, root->tree_data, &root_checksum, error))
-    goto out;
-
-  now = g_date_time_new_now_utc ();
-  commit = g_variant_new ("(u@a{sv}ssstss)",
-                          GUINT32_TO_BE (OSTREE_COMMIT_VERSION),
-                          metadata ? metadata : create_empty_gvariant_dict (),
-                          parent ? parent : "",
-                          subject, body ? body : "",
-                          GUINT64_TO_BE (g_date_time_to_unix (now)),
-                          g_checksum_get_string (root_checksum),
-                          root->metadata_sha256);
-  g_variant_ref_sink (commit);
-  if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
-                               commit, &ret_commit, error))
-    goto out;
-
-  if (!ostree_repo_write_ref (self, NULL, branch, g_checksum_get_string (ret_commit), error))
-    goto out;
-
-  ret = TRUE;
-  *out_commit = ret_commit;
- out:
-  if (root_checksum)
-    g_checksum_free (root_checksum);
-  ot_clear_gvariant (&commit);
-  if (now)
-    g_date_time_unref (now);
-  return ret;
-}
-
-static gboolean
-import_root (OstreeRepo           *self,
-             const char           *base,
-             ParsedDirectoryData **out_root,
-             GError              **error)
-{
-  gboolean ret = FALSE;
-  ParsedDirectoryData *ret_root = NULL;
-  GVariant *root_metadata = NULL;
-  GChecksum *root_meta_checksum = NULL;
-
-  if (!import_directory_meta (self, base, &root_metadata, &root_meta_checksum, error))
-    goto out;
-
-  ret_root = g_new0 (ParsedDirectoryData, 1);
-  ret_root->tree_data = parsed_tree_data_new ();
-  ret_root->meta_data = root_metadata;
-  root_metadata = NULL;
-  ret_root->metadata_sha256 = g_strdup (g_checksum_get_string (root_meta_checksum));
-
-  ret = TRUE;
-  *out_root = ret_root;
-  ret_root = NULL;
- out:
-  ot_clear_gvariant (&root_metadata);
-  if (root_meta_checksum)
-    g_checksum_free (root_meta_checksum);
-  parsed_directory_data_free (ret_root);
-  return ret;
-}
-
-gboolean      
-ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
-                                     const char   *branch,
-                                     const char   *parent,
-                                     const char   *subject,
-                                     const char   *body,
-                                     GVariant     *metadata,
-                                     const char   *base,
-                                     int           fd,
-                                     char          separator,
-                                     GChecksum   **out_commit,
-                                     GError      **error)
 {
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   gboolean ret = FALSE;
-  ParsedDirectoryData *root = NULL;
   GChecksum *ret_commit_checksum = NULL;
-  GUnixInputStream *in = NULL;
-  GDataInputStream *datain = NULL;
-  char *filename = NULL;
-  gsize filename_len;
-  GError *temp_error = NULL;
-  GVariant *root_metadata = NULL;
-  GChecksum *root_meta_checksum = NULL;
+  GChecksum *root_metadata_checksum = NULL;
+  GChecksum *root_contents_checksum = NULL;
   char *current_head = NULL;
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -1465,39 +1250,14 @@ ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
   if (parent == NULL)
     parent = branch;
 
-  /* We're overwriting the tree */
-  if (!import_root (self, base, &root, error))
-    goto out;
-
   if (!ostree_repo_resolve_rev (self, parent, TRUE, &current_head, error))
     goto out;
 
-  in = (GUnixInputStream*)g_unix_input_stream_new (fd, FALSE);
-  datain = g_data_input_stream_new ((GInputStream*)in);
+  if (!import_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
+    goto out;
 
-  while ((filename = g_data_input_stream_read_upto (datain, &separator, 1,
-                                                    &filename_len, NULL, &temp_error)) != NULL)
-    {
-      if (!g_data_input_stream_read_byte (datain, NULL, &temp_error))
-        {
-          if (temp_error != NULL)
-            {
-              g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
-              goto out;
-            }
-        }
-      if (!add_one_path_to_tree_and_import (self, base, filename, root->tree_data, error))
-        goto out;
-      g_free (filename);
-      filename = NULL;
-    }
-  if (filename == NULL && temp_error != NULL)
-    {
-      g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
-      goto out;
-    }
-  if (!commit_parsed_tree (self, branch, current_head, subject, body, metadata,
-                           root, &ret_commit_checksum, error))
+  if (!import_commit (self, branch, current_head, subject, body, metadata,
+                      root_contents_checksum, root_metadata_checksum, &ret_commit_checksum, error))
     goto out;
   
   ret = TRUE;
@@ -1507,13 +1267,10 @@ ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
   if (ret_commit_checksum)
     g_checksum_free (ret_commit_checksum);
   g_free (current_head);
-  ot_clear_gvariant (&root_metadata);
-  if (root_meta_checksum)
-    g_checksum_free (root_meta_checksum);
-  g_clear_object (&datain);
-  g_clear_object (&in);
-  g_free (filename);
-  parsed_directory_data_free (root);
+  if (root_metadata_checksum)
+    g_checksum_free (root_metadata_checksum);
+  if (root_contents_checksum)
+    g_checksum_free (root_contents_checksum);
   return ret;
   
 }
index 36a8f56b3b6425ed10aa342d72110e81b5c368ea..f8b064aa320bc806f574ca7a38cfb829137747e6 100644 (file)
@@ -110,17 +110,16 @@ gboolean      ostree_repo_load_variant_checked (OstreeRepo  *self,
                                                 GVariant     **out_variant,
                                                 GError       **error);
 
-gboolean      ostree_repo_commit_from_filelist_fd (OstreeRepo   *self,
-                                                   const char   *branch,
-                                                   const char   *parent,
-                                                   const char   *subject,
-                                                   const char   *body,
-                                                   GVariant     *metadata,
-                                                   const char   *base,
-                                                   int           fd,
-                                                   char          separator,
-                                                   GChecksum   **out_commit,
-                                                   GError      **error);
+gboolean      ostree_repo_commit (OstreeRepo   *self,
+                                  const char   *branch,
+                                  const char   *parent,
+                                  const char   *subject,
+                                  const char   *body,
+                                  GVariant     *metadata,
+                                  GFile        *base,
+                                  GChecksum   **out_commit,
+                                  GCancellable *cancellable,
+                                  GError      **error);
 
 gboolean      ostree_repo_checkout (OstreeRepo *self,
                                     const char   *ref,
index 275e16dcd96de2da1ad2f3db82acbcc0baf792b1..f3955f1606384a9be2a445c17450dc207e76c7ec 100644 (file)
 
 #include <glib/gi18n.h>
 
-static gboolean separator_null;
-static int from_fd = -1;
-static gboolean from_stdin;
-static char *from_file;
 static char *metadata_text_path;
 static char *metadata_bin_path;
 static char *subject;
@@ -47,159 +43,22 @@ static GOptionEntry options[] = {
   { "metadata-variant", 0, 0, G_OPTION_ARG_FILENAME, &metadata_bin_path, "File containing serialized variant, in host endianness", "path" },
   { "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
   { "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
-  { "from-fd", 0, 0, G_OPTION_ARG_INT, &from_fd, "Read new tree files from fd", "file descriptor" },
-  { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &from_stdin, "Read new tree files from stdin", "file descriptor" },
-  { "from-file", 0, 0, G_OPTION_ARG_FILENAME, &from_file, "Read new tree files from another file", "path" },
-  { "separator-null", 0, 0, G_OPTION_ARG_NONE, &separator_null, "", "Use '\\0' as filename separator, as with find -print0" },
   { NULL }
 };
 
-typedef struct {
-  GFile *dir;
-  char separator;
-  GOutputStream *out;
-  GCancellable *cancellable;
-} FindThreadData;
-
-static gboolean
-find (const char *basepath,
-      GFile *dir,
-      char separator,
-      GOutputStream *out,
-      GCancellable *cancellable,
-      GError  **error);
-
-static gboolean
-find_write_child (const char *basepath,
-                  GFile      *dir,
-                  char        separator,
-                  GOutputStream *out,
-                  GFileInfo  *finfo,
-                  GCancellable *cancellable,
-                  GError    **error)
-{
-  gboolean ret = FALSE;
-  guint32 type;
-  const char *name;
-  char buf[1];
-  const char *child_path = NULL;
-  GString *child_trimmed_path = NULL;
-  GFile *child = NULL;
-  gsize bytes_written;
-
-  type = g_file_info_get_attribute_uint32 (finfo, "standard::type");
-  name = g_file_info_get_attribute_byte_string (finfo, "standard::name");
-
-  child = g_file_get_child (dir, name);
-
-  if (type == G_FILE_TYPE_DIRECTORY)
-    {
-      if (!find (basepath, child, separator, out, cancellable, error))
-        goto out;
-    }
-
-  child_path = ot_gfile_get_path_cached (child);
-  child_trimmed_path = g_string_new (child_path + strlen (basepath));
-  if (!*(child_trimmed_path->str))
-    {
-      /* do nothing - we implicitly add the root . */
-    }
-  else
-    {
-      g_assert (*(child_trimmed_path->str) == '/');
-      g_string_insert_c (child_trimmed_path, 0, '.');
-
-      if (!g_output_stream_write_all (out, child_trimmed_path->str, child_trimmed_path->len,
-                                      &bytes_written, cancellable, error))
-        goto out;
-      buf[0] = separator;
-      if (!g_output_stream_write_all (out, buf, 1, &bytes_written,
-                                      cancellable, error))
-        goto out;
-    }
-      
-  ret = TRUE;
- out:
-  g_string_free (child_trimmed_path, TRUE);
-  child_trimmed_path = NULL;
-  child_path = NULL;
-  g_clear_object (&child);
-  return ret;
-}
-
-static gboolean
-find (const char *basepath,
-      GFile *dir,
-      char separator,
-      GOutputStream *out,
-      GCancellable *cancellable,
-      GError  **error)
-{
-  gboolean ret = FALSE;
-  GError *temp_error = NULL;
-  GFileEnumerator *enumerator = NULL;
-  GFileInfo *finfo = NULL;
-
-  enumerator = g_file_enumerate_children (dir, "standard::type,standard::name", 
-                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                          cancellable, error);
-  if (!enumerator)
-    goto out;
-
-  while ((finfo = g_file_enumerator_next_file (enumerator, cancellable, error)) != NULL)
-    {
-      if (!find_write_child (basepath, dir, separator, out, finfo, cancellable, error))
-        goto out;
-      g_clear_object (&finfo);
-    }
-  if (temp_error)
-    {
-      g_propagate_error (error, temp_error);
-      goto out;
-    }
-
-  ret = TRUE;
- out:
-  g_clear_object (&finfo);
-  g_clear_object (&enumerator);
-  return ret;
-}
-
-static gpointer
-find_thread (gpointer data)
-{
-  FindThreadData *tdata = data;
-  GError *error = NULL;
-  const char *path;
-  
-  path = ot_gfile_get_path_cached (tdata->dir);
-  if (!find (path, tdata->dir, tdata->separator, tdata->out,
-             tdata->cancellable, &error))
-    {
-      g_printerr ("%s", error->message);
-      g_clear_error (&error);
-    }
-  g_clear_object (&(tdata->dir));
-  g_clear_object (&(tdata->out));
-  return NULL;
-}
-
 gboolean
 ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **error)
 {
   GOptionContext *context;
   gboolean ret = FALSE;
   OstreeRepo *repo = NULL;
-  char *dir = NULL;
+  char *dirpath = NULL;
+  GFile *dir = NULL;
   GChecksum *commit_checksum = NULL;
   char separator;
   GVariant *metadata = NULL;
   GMappedFile *metadata_mappedf = NULL;
   GFile *metadata_f = NULL;
-  gboolean temp_fd = -1;
-  int pipefd[2] = { -1, -1 };
-  GOutputStream *out = NULL;
-  FindThreadData fdata;
 
   context = g_option_context_new ("[DIR] - Commit a new revision");
   g_option_context_add_main_entries (context, options, NULL);
@@ -208,22 +67,22 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
     goto out;
 
   if (argc > 1)
-    dir = g_strdup (argv[1]);
+    dirpath = g_strdup (argv[1]);
   else
-    dir = g_get_current_dir ();
+    dirpath = g_get_current_dir ();
 
-  if (g_str_has_suffix (dir, "/"))
-    dir[strlen (dir) - 1] = '\0';
+  if (g_str_has_suffix (dirpath, "/"))
+    dirpath[strlen (dirpath) - 1] = '\0';
 
-  separator = separator_null ? '\0' : '\n';
-
-  if (!*dir)
+  if (!*dirpath)
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                    "Invalid empty directory");
       goto out;
     }
 
+  dir = ot_gfile_new_for_path (dirpath);
+
   if (metadata_text_path || metadata_bin_path)
     {
       metadata_mappedf = g_mapped_file_new (metadata_text_path ? metadata_text_path : metadata_bin_path, FALSE, error);
@@ -266,62 +125,15 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
       goto out;
     }
 
-  if (!(from_file || from_fd >= 0 || from_stdin))
-    {
-      /* We're using the current directory */
-
-    }
-
-  if (from_stdin)
-    from_fd = 0;
-  else if (from_file)
-    {
-      temp_fd = ot_util_open_file_read (from_file, error);
-      if (temp_fd < 0)
-        {
-          g_prefix_error (error, "Failed to open '%s': ", from_file);
-          goto out;
-        }
-      from_fd = temp_fd;
-    }
-  else
-    {
-      if (pipe (pipefd) < 0)
-        {
-          ot_util_set_error_from_errno (error, errno);
-          goto out;
-        }
-
-      out = (GOutputStream*)g_unix_output_stream_new (pipefd[1], TRUE);
-      from_fd = pipefd[0];
-
-      fdata.dir = ot_gfile_new_for_path (dir);
-      fdata.separator = separator;
-      fdata.out = out;
-      fdata.cancellable = NULL;
-
-      if (g_thread_create_full (find_thread, &fdata, 0, FALSE, FALSE, G_THREAD_PRIORITY_NORMAL, error) == NULL)
-        goto out;
-
-      out = NULL;
-    }
-
-  if (!ostree_repo_commit_from_filelist_fd (repo, branch, parent, subject, body, metadata,
-                                            dir, from_fd, separator,
-                                            &commit_checksum, error))
+  if (!ostree_repo_commit (repo, branch, parent, subject, body, metadata,
+                           dir, &commit_checksum, NULL, error))
     goto out;
 
   ret = TRUE;
   g_print ("%s\n", g_checksum_get_string (commit_checksum));
  out:
-  g_clear_object (&out);
-  if (temp_fd >= 0)
-    (void)close (temp_fd);
-  if (pipefd[0] > 0)
-    (void) close (pipefd[0]);
-  if (pipefd[1] > 0)
-    (void) close (pipefd[1]);
-  g_free (dir);
+  g_free (dirpath);
+  g_clear_object (&dir);
   if (metadata_mappedf)
     g_mapped_file_unref (metadata_mappedf);
   if (context)
index 0db1527872985ac56d919e36302ab893c21562e9..02a060adf7c97ba8aa8a3a7725ee74246eecfa3b 100755 (executable)
@@ -71,8 +71,8 @@ mkdir -p another/nested/tree
 echo anotherone > another/nested/tree/1
 echo whee2 > another/whee
 # FIXME - remove grep for .
-find | grep -v '^\.$' | $OSTREE commit -b test2 -s "From find" --from-stdin
-echo "ok stdin commit"
+$OSTREE commit -b test2 -s "Another commit"
+echo "ok commit"
 
 cd ${test_tmpdir}
 $OSTREE checkout test2 $test_tmpdir/checkout-test2-3
index 1a747dc64bc9584e67c9c414c48a522e9261e2e6..51d2f8d89898c512e861a9473e1ef7c848cc2290 100755 (executable)
@@ -35,7 +35,7 @@ echo 'an ELF file' > usr/lib/libfoo.so
 mkdir -p usr/share
 echo 'some data' > usr/share/foo.data
 
-find | grep -v '^\.$' | $OSTREE commit -b artifact-libfoo-runtime -s 'Build 12345 of libfoo' --from-stdin
+$OSTREE commit -b artifact-libfoo-runtime -s 'Build 12345 of libfoo'
 
 cd "${test_tmpdir}"
 mkdir artifact-libfoo-devel
@@ -45,7 +45,7 @@ echo 'a header' > usr/include/foo.h
 mkdir -p usr/share/doc
 echo 'some documentation' > usr/share/doc/foo.txt
 
-find | grep -v '^\.$' | $OSTREE commit -b artifact-libfoo-devel -s 'Build 12345 of libfoo' --from-stdin
+$OSTREE commit -b artifact-libfoo-devel -s 'Build 12345 of libfoo'
 
 cd "${test_tmpdir}"
 mkdir artifact-barapp
@@ -53,7 +53,7 @@ cd artifact-barapp
 mkdir -p usr/bin
 echo 'another ELF file' > usr/bin/bar
 
-find | grep -v '^\.$' | $OSTREE commit -b artifact-barapp -s 'Build 42 of barapp' --from-stdin
+$OSTREE commit -b artifact-barapp -s 'Build 42 of barapp'
 
 echo 'ok artifacts committed'